package com.engine.salary.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.oceanbase.jdbc.StringUtils;
import com.cloudstore.eccom.pc.table.WeaTable;
import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.encrypt.EncryptUtil;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.hrm.dto.HrmInfoDTO;
import com.engine.salary.entity.hrm.param.HrmQueryParam;
import com.engine.salary.entity.siaccount.dto.InsuranceCompensationDTO;
import com.engine.salary.entity.siaccount.param.CompensationParam;
import com.engine.salary.entity.siaccount.po.InsuranceAccountBatchPO;
import com.engine.salary.entity.siaccount.po.InsuranceAccountDetailPO;
import com.engine.salary.entity.siaccount.po.InsuranceCompensationConfigPO;
import com.engine.salary.entity.siaccount.po.InsuranceCompensationPO;
import com.engine.salary.entity.sicategory.po.ICategoryPO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.datacollection.UseEmployeeTypeEnum;
import com.engine.salary.enums.siaccount.PaymentStatusEnum;
import com.engine.salary.enums.sicategory.DeleteTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.datacollection.EmployMapper;
import com.engine.salary.mapper.siaccount.InsuranceAccountBatchMapper;
import com.engine.salary.mapper.siaccount.InsuranceAccountDetailMapper;
import com.engine.salary.mapper.siaccount.InsuranceCompensationConfigMapper;
import com.engine.salary.mapper.siaccount.InsuranceCompensationMapper;
import com.engine.salary.mapper.sicategory.ICategoryMapper;
import com.engine.salary.mapper.taxagent.TaxAgentMapper;
import com.engine.salary.service.*;
import com.engine.salary.util.SalaryAssert;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.page.Column;
import com.google.common.collect.Lists;
import com.engine.salary.util.db.IdGenerator;
import org.springframework.beans.BeanUtils;
import weaver.hrm.User;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: sy
 * @Description: 福利台账-调差实现类
 * @Date: 2022/11/23
 **/
public class SICompensationServiceImpl extends Service implements SICompensationService {
    private EncryptUtil encryptUtil = new EncryptUtil();

    private InsuranceAccountDetailMapper getInsuranceAccountDetailMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountDetailMapper.class);
    }

    private EmployMapper getEmployMapper() {
        return MapperProxyFactory.getProxy(EmployMapper.class);
    }

    public SICategoryService getSICategoryService(User user) {
        return ServiceUtil.getService(SICategoryServiceImpl.class, user);
    }

    private SIAccountService getSIAccountService(User user) {
        return ServiceUtil.getService(SIAccountServiceImpl.class, user);
    }

    private InsuranceCompensationMapper getInsuranceCompensationMapper() {
        return MapperProxyFactory.getProxy(InsuranceCompensationMapper.class);
    }

    private InsuranceCompensationConfigMapper getInsuranceCompensationConfigMapper() {
        return MapperProxyFactory.getProxy(InsuranceCompensationConfigMapper.class);
    }

    public ColumnBuildService getColumnBuildService(User user) {
        return ServiceUtil.getService(ColumnBuildServiceImpl.class, user);
    }

    private ICategoryMapper getICategoryMapper() {
        return MapperProxyFactory.getProxy(ICategoryMapper.class);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    private InsuranceAccountBatchMapper getInsuranceAccountBatchMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountBatchMapper.class);
    }

    private TaxAgentMapper getTaxAgentMapper() {
        return MapperProxyFactory.getProxy(TaxAgentMapper.class);
    }

    /**
     * 可调差人员
     */
    @Override
    public List<HrmInfoDTO> getEmployeeListToCompensation(HrmQueryParam param) {
        // 当前登录人员
        Long currentEmployeeId = (long) user.getUID();

        //查询账单月份+个税扣缴义务人下的社保福利正常缴纳人员列表
        List<InsuranceAccountDetailPO> normalDataList = getInsuranceAccountDetailMapper().queryNormalListByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
        List<Long> empIds = normalDataList.stream().map(InsuranceAccountDetailPO::getEmployeeId).collect(Collectors.toList());
        //生成人员id和bill_detail.id的对应map
        Map<Long, Long> empIdToTargetMap = SalaryEntityUtil.convert2Map(normalDataList, InsuranceAccountDetailPO::getEmployeeId, InsuranceAccountDetailPO::getId);

        List<HrmInfoDTO> resultData = new ArrayList<>();
        if (empIds.size() > 0) {
            List<List<Long>> partition = Lists.partition(empIds, 1000);
            partition.forEach(p -> {
                param.setIds(p);
                resultData.addAll(getEmployMapper().listHrmInfoByIdAndName(param));
                resultData.addAll(getEmployMapper().listExtHrmInfoByIdAndName(param));
            });

        }
        List<HrmInfoDTO> finalResultData = new ArrayList<>();
        for (HrmInfoDTO dto : resultData) {
            dto.setTarget(empIdToTargetMap.get(dto.getEmployeeId()));
            finalResultData.add(dto);
        }

        return finalResultData;
    }
//    public PageInfo<HrmInfoDTO> getEmployeeListToCompensation(HrmQueryParam param) {
//        // 当前登录人员
//        Long currentEmployeeId = (long) user.getUID();
//
//        //查询账单月份+个税扣缴义务人下的社保福利正常缴纳人员列表
//        List<InsuranceAccountDetailPO> normalDataList = getInsuranceAccountDetailMapper().queryNormalListByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
//        List<Long> empIds = normalDataList.stream().map(InsuranceAccountDetailPO::getEmployeeId).collect(Collectors.toList());
//
//        List<HrmInfoDTO> resultData = new ArrayList<>();
//        if (empIds.size() > 0) {
//            List<List<Long>> partition = Lists.partition(empIds, 1000);
//            partition.forEach(p -> {
//                param.setIds(p);
//                resultData.addAll(getEmployMapper().listHrmInfoByIdAndName(param));
//            });
//
//        }
//
//        // 分页
//        PageInfo<HrmInfoDTO> page = new PageInfo<>();
//        if (resultData.size() == 0) {
//            return page;
//        }
//        page.setTotal(resultData.size());
//
//        page.setList(SalaryPageUtil.subList(param.getPageNum(), param.getPageSize(), resultData));
//        page.setPageSize(param.getPageSize());
//        page.setPageNum(param.getPageNum());
//
//
//        return page;
//    }

    /**
     * 调差福利项
     * @param id InsuranceAccountDetailPO.id
     */
    @Override
    public List<Map<String, String>> compensationCategoryType(Long id) {
        SalaryAssert.notNull(id, SalaryI18nUtil.getI18nLabel(120999, "调差对象必选"));
        InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(id);
        if (insuranceAccountDetailPO == null) {
            return Lists.newArrayList();
        }
        encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
        List<Map<String, String>> result = new ArrayList<>();
        String socialComJson = insuranceAccountDetailPO.getSocialComJson();
        if (StringUtils.isNotBlank(socialComJson)) {
            Map<String, String> categoryIdNameMap = getSICategoryService(user).categoryIdNameMap();
            Map<String, String> socialJson = JSON.parseObject(socialComJson, new HashMap<String, String>().getClass());
            for (Map.Entry<String, String> entry : socialJson.entrySet()) {
                Map<String, String> temp = new HashMap<>();
                String insuranceId = entry.getKey();
                if (StringUtils.isNotBlank(categoryIdNameMap.get(insuranceId))) {
                    temp.put("id", insuranceId);
                    temp.put("content", categoryIdNameMap.get(insuranceId));
                    result.add(temp);
                }
            }
        }
        return result;
    }

    /**
     * 获取当前调差福利类型-公司方支出总计
     */
    @Override
    public List<Map<String, String>> compensationComTotal(List<CompensationParam> paramList) {
        List<Map<String, String>> resultList = new ArrayList<>();
        paramList.forEach(compensation -> {
            Map<String, String> temp = new HashMap<>();
            temp.put("employeeId", compensation.getEmployeeId());
            if (StringUtils.isBlank(compensation.getCategoryType()) || compensation.getTarget() == null) {
                temp.put("error", SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
                temp.put("totalNum", "0");
            } else {

                InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(compensation.getTarget());
                if (insuranceAccountDetailPO == null) {
                    temp.put("error", SalaryI18nUtil.getI18nLabel(121038, "当前月在该缴纳组织下没有核算记录"));
                    temp.put("totalNum", "0");
                } else {
                    encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
                    //判断是否已有调差数据（个税扣缴义务人+账单月份+人员id）
//                    InsuranceCompensationPO nowCompensation = getInsuranceCompensationMapper().getOneByBillMonthPayOrgEmpId(InsuranceCompensationPO.builder()
//                            .billMonth(insuranceAccountDetailPO.getBillMonth())
//                            .paymentOrganization(insuranceAccountDetailPO.getPaymentOrganization())
//                            .employeeId(insuranceAccountDetailPO.getEmployeeId())
//                            .build());
//
//                    if (nowCompensation != null) {
//                        temp.put("error", SalaryI18nUtil.getI18nLabel(121039, "当前月在该缴纳组织下已存在调差数据"));
//                    }

                    //处理调差数据
                    BigDecimal total = new BigDecimal("0");
                    List<String> categoryTypeList = Arrays.asList(compensation.getCategoryType().split(","));

                    if (StringUtils.isNotBlank(insuranceAccountDetailPO.getSocialComJson())) {
                        Map<String, String> socialJson = JSON.parseObject(insuranceAccountDetailPO.getSocialComJson(), new HashMap<String, String>().getClass());
                        for (Map.Entry<String, String> entry : socialJson.entrySet()) {
                            String insuranceId = entry.getKey();
                            String num = entry.getValue();
                            if (categoryTypeList.contains(insuranceId)) {
                                total = total.add(new BigDecimal(num));
                            }
                        }
                    }

                    temp.put("totalNum", total.toPlainString());
                }

            }
            resultList.add(temp);
        });
//        paramList.forEach((paymentOrganization, compensationList) -> {
//            List<Map<String, String>> paymentList = new ArrayList<>();
//            compensationList.forEach(compensation -> {
//                Map<String, String> temp = new HashMap<>();
//                temp.put("employeeId", compensation.getEmployeeId());
//                if (StringUtils.isBlank(compensation.getCategoryType()) || compensation.getTarget() == null) {
//                    temp.put("error", SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
//                    temp.put("totalNum", "0");
//                } else {
//
//                    InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(compensation.getTarget());
//                    if (insuranceAccountDetailPO == null) {
//                        temp.put("error", SalaryI18nUtil.getI18nLabel(121038, "当前月在该缴纳组织下没有核算记录"));
//                    }
//                    InsuranceAccountDetailPOEncrypt.decryptItem(insuranceAccountDetailPO);
//                    BigDecimal total = new BigDecimal("0");
//                    List<String> categoryTypeList = Arrays.asList(compensation.getCategoryType().split(","));
//
//                    if (StringUtils.isNotBlank(insuranceAccountDetailPO.getSocialComJson())) {
//                        Map<String, String> socialJson = JSON.parseObject(insuranceAccountDetailPO.getSocialComJson(), new HashMap<String, String>().getClass());
//                        for (Map.Entry<String, String> entry : socialJson.entrySet()) {
//                            String insuranceId = entry.getKey();
//                            String num = entry.getValue();
//                            if (categoryTypeList.contains(insuranceId)) {
//                                total = total.add(new BigDecimal(num));
//                            }
//                        }
//                    }
//
//                    temp.put("totalNum", total.toPlainString());
//                }
//                paymentList.add(temp);
//            });
//            result.put(paymentOrganization, paymentList);
//        });
        return resultList;
    }

    @Override
    public Map<String, Object> compensationAccount(List<InsuranceCompensationDTO> list) {

        long currentEmployeeId = user.getUID();
//        List<DataCollectionEmployee> allEmployees = getEmployMapper().listAll();
        List<DataCollectionEmployee> allEmployees = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);
        Map<Long, String> usernameMap = SalaryEntityUtil.convert2Map(allEmployees, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getUsername);

        Map<String, Object> result = new HashMap<>();
        List<String> errorList = new ArrayList<>();
        List<Long> idList = new ArrayList<>();
        //过滤
        list = list.stream().collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() ->
                                new TreeSet<>(Comparator.comparing((o -> o.getTarget() + ";" + o.getAdjustTo() + ";" + o.getCategoryType())))), ArrayList::new));

        //根据target分组
        Map<Long, List<InsuranceCompensationDTO>> compensationGroupInfoMap= list.stream().collect(Collectors.groupingBy(InsuranceCompensationDTO::getTarget));
        //取福利项id和name的关联map
        List<ICategoryPO> socialWelfareList = getICategoryMapper().listAll().stream().filter(e -> e.getWelfareType() == 1).collect(Collectors.toList());
        Map<Long, String> welfareNameMap = socialWelfareList.stream().collect(Collectors.toMap(ICategoryPO::getId, ICategoryPO::getInsuranceName, (key1, key2) -> key2));
        for (InsuranceCompensationDTO param : list) {
            //判断“统计调差福利类型”即categoryType中，是否存在同保存批次重复福利项
            List<InsuranceCompensationDTO> waitJudgeCompensations = compensationGroupInfoMap.get(param.getTarget()).stream().
                    filter(f -> !f.getTarget().equals(param.getTarget()) && !f.getAdjustTo().equals(param.getAdjustTo()) && !f.getCategoryType().equals(param.getCategoryType())).collect(Collectors.toList());
            if (waitJudgeCompensations.size() > 0) {
                boolean judgeResult = true;
                for (InsuranceCompensationDTO judgeParam : waitJudgeCompensations) {
                    List<String> toDealWelfareTypeList = Arrays.asList(param.getCategoryType().split(","));
                    List<String> toJudgeWelfareTypeList = Arrays.asList(judgeParam.getCategoryType().split(","));
//                    toDealWelfareTypeList.retainAll(toJudgeWelfareTypeList);
                    List<String> intersectionList = (List<String>) SalaryEntityUtil.intersectionForList(toDealWelfareTypeList, toJudgeWelfareTypeList);
                    if (intersectionList.size() > 0) {
                        StringBuilder toDealWelfareNames = new StringBuilder();
                        StringBuilder sameWelfareNames = new StringBuilder();
                        for(String str : toDealWelfareTypeList) {
                            if (welfareNameMap.get(Long.valueOf(str)) != null) {
                                toDealWelfareNames.append(welfareNameMap.get(Long.valueOf(str))).append("、");
                            }
                        }
                        for(String str : intersectionList) {
                            if (welfareNameMap.get(Long.valueOf(str)) != null) {
                                sameWelfareNames.append(welfareNameMap.get(Long.valueOf(str))).append("、");
                            }
                        }
                        errorList.add(usernameMap.get(param.getEmployeeId()) + "-" + toDealWelfareNames.deleteCharAt(toDealWelfareNames.length() - 1)
                                + "-调差失败：提交数据中，统计调差福利类型有重合部分！" + "重合福利部分为：" + sameWelfareNames.deleteCharAt(sameWelfareNames.length() - 1));
                        judgeResult = false;
                        break;
                    }
                }
                if (!judgeResult) {
                    continue;
                }

            }

            if (StringUtils.isBlank(param.getAdjustmentTotal()) || "0".equals(param.getAdjustmentTotal()) || "0.00".equals(param.getAdjustmentTotal())) {
                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：调差数额不正确！");
                continue;
            }
            if (StringUtils.isBlank(param.getCompanyTotal()) || "0".equals(param.getCompanyTotal()) || "0.00".equals(param.getCompanyTotal())) {
                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：公司核算金额为0，请检查数据是否属实或者当前人员已存在该月调差数据！");
                continue;
            }
            if (param.getAdjustTo() == null) {
                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：调差到的福利未设置！");
                continue;
            }
            InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(param.getTarget());
            if (insuranceAccountDetailPO == null) {
                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：调差对象不存在！");
                continue;
            }

            if (!param.getCategoryType().contains(param.getAdjustTo().toString())) {
                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：调差到的福利未正确设置！");
                continue;
            }

            //判断是否已有调差数据（个税扣缴义务人+账单月份+人员id）
//            InsuranceCompensationPO nowCompensation = getInsuranceCompensationMapper().getOneByBillMonthPayOrgEmpId(InsuranceCompensationPO.builder()
//                    .billMonth(insuranceAccountDetailPO.getBillMonth())
//                    .paymentOrganization(insuranceAccountDetailPO.getPaymentOrganization())
//                    .employeeId(insuranceAccountDetailPO.getEmployeeId())
//                    .build());
//            if (nowCompensation != null) {
//                errorList.add(usernameMap.get(param.getEmployeeId()) + "-调差失败：调差对象在当前月该缴纳组织下已存在调差数据！");
//                continue;
//            }
            List<InsuranceCompensationPO> nowCompensationList = getInsuranceCompensationMapper().getListByBillMonthPayOrgEmpId(InsuranceCompensationPO.builder()
                    .billMonth(insuranceAccountDetailPO.getBillMonth())
                    .paymentOrganization(insuranceAccountDetailPO.getPaymentOrganization())
                    .employeeId(insuranceAccountDetailPO.getEmployeeId())
                    .build());
            if (nowCompensationList.size() > 0) {
                boolean judgeResult = true;
                for (InsuranceCompensationPO judgePO : nowCompensationList) {
                    List<String> toDealWelfareTypeList = Arrays.asList(param.getCategoryType().split(","));
                    List<String> toJudgeWelfareTypeList = Arrays.asList(judgePO.getCategoryType().split(","));

                    List<String> intersectionList = (List<String>) SalaryEntityUtil.intersectionForList(toDealWelfareTypeList, toJudgeWelfareTypeList);
                    if (intersectionList.size() > 0) {
                        StringBuilder toDealWelfareNames = new StringBuilder();
                        StringBuilder sameWelfareNames = new StringBuilder();
                        for(String str : toDealWelfareTypeList) {
                            if (welfareNameMap.get(Long.valueOf(str)) != null) {
                                toDealWelfareNames.append(welfareNameMap.get(Long.valueOf(str))).append("、");
                            }
                        }
                        for(String str : intersectionList) {
                            if (welfareNameMap.get(Long.valueOf(str)) != null) {
                                sameWelfareNames.append(welfareNameMap.get(Long.valueOf(str))).append("、");
                            }
                        }
                        errorList.add(usernameMap.get(param.getEmployeeId()) + "-" + toDealWelfareNames.deleteCharAt(toDealWelfareNames.length() - 1)
                                + "-调差失败：相同福利不可以多次调差！" + "相同部分为：" + sameWelfareNames.deleteCharAt(sameWelfareNames.length() - 1));
                        judgeResult = false;
                        break;
                    }
                }
                if (!judgeResult) {
                    continue;
                }
            }


            encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
            if (StringUtils.isNotBlank(insuranceAccountDetailPO.getSocialComJson())) {
                Map<String, String> socialJson = JSON.parseObject(insuranceAccountDetailPO.getSocialComJson(), new HashMap<String, String>().getClass());
                for (Map.Entry<String, String> entry : socialJson.entrySet()) {
                    String insuranceId = entry.getKey();
                    String num = entry.getValue();
                    if (Objects.equals(String.valueOf(param.getAdjustTo()), insuranceId)) {
                        BigDecimal adjustmentTo = new BigDecimal(param.getAdjustmentTotal());
                        // 调差单位缴纳明细
                        BigDecimal insuranceNum = new BigDecimal(num);
                        insuranceNum = insuranceNum.add(adjustmentTo);
                        socialJson.replace(insuranceId, insuranceNum.toPlainString());
                        insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialJson));
                        // 调差单位合计
                        BigDecimal comSum = new BigDecimal(insuranceAccountDetailPO.getComSum());
                        comSum = comSum.add(adjustmentTo);
                        insuranceAccountDetailPO.setComSum(comSum.toPlainString());
                        // 调差社保单位合计
                        BigDecimal socialComSum = new BigDecimal(insuranceAccountDetailPO.getSocialComSum());
                        socialComSum = socialComSum.add(adjustmentTo);
                        insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
                        // 调差社保合计
                        BigDecimal socialSum = new BigDecimal(insuranceAccountDetailPO.getSocialSum());
                        socialSum = socialSum.add(adjustmentTo);
                        insuranceAccountDetailPO.setSocialSum(socialSum.toPlainString());
                        // 调差合计
                        BigDecimal totalSum = new BigDecimal(insuranceAccountDetailPO.getTotal());
                        totalSum = totalSum.add(adjustmentTo);
                        insuranceAccountDetailPO.setTotal(totalSum.toPlainString());
                        //更新社保调差后的明细
                        encryptUtil.encrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
                        getInsuranceAccountDetailMapper().updateById(insuranceAccountDetailPO);
                        //新建调差记录
                        InsuranceCompensationPO insuranceCompensationPO = new InsuranceCompensationPO();
                        insuranceCompensationPO.setId(IdGenerator.generate());
                        insuranceCompensationPO.setAdjustmentTotal(param.getAdjustmentTotal());
                        insuranceCompensationPO.setAdjustTo(param.getAdjustTo());
                        insuranceCompensationPO.setBillMonth(param.getBillMonth());
                        insuranceCompensationPO.setCompanyTotal(param.getCompanyTotal());
                        insuranceCompensationPO.setCreator(currentEmployeeId);
                        insuranceCompensationPO.setCategoryType(param.getCategoryType());
                        insuranceCompensationPO.setCreateTime(new Date());
                        insuranceCompensationPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
                        insuranceCompensationPO.setCountryTotal(param.getCountryTotal());
                        insuranceCompensationPO.setEmployeeId(insuranceAccountDetailPO.getEmployeeId());

                        insuranceCompensationPO.setPaymentOrganization(insuranceAccountDetailPO.getPaymentOrganization());
                        insuranceCompensationPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
                        insuranceCompensationPO.setWelfareType(param.getWelfareType());
                        insuranceCompensationPO.setUpdateTime(new Date());
                        getInsuranceCompensationMapper().insert(insuranceCompensationPO);

                        idList.add(insuranceCompensationPO.getId());
//                        result.put(param.getOriginId(), insuranceCompensationPO.getId().toString());
                        //记录操作日志
                        InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(insuranceAccountDetailPO.getBillMonth(), insuranceAccountDetailPO.getPaymentOrganization());
                        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(insuranceAccountDetailPO.getPaymentOrganization());
                        DataCollectionEmployee empInfo = getSalaryEmployeeService(user).getEmployeeById(insuranceAccountDetailPO.getEmployeeId());
                        LoggerContext<InsuranceCompensationPO> loggerContext = new LoggerContext();
                        loggerContext.setUser(user);
                        loggerContext.setTargetId(String.valueOf(targetPO.getId()));
                        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + insuranceAccountDetailPO.getBillMonth() + "-" + empInfo.getUsername());
                        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
                        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-新增调差"));
                        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-新增调差")
                                + ":" + taxAgentInfo.getName() + "-" + insuranceAccountDetailPO.getBillMonth() + "-" + empInfo.getUsername());
                        loggerContext.setNewValues(insuranceCompensationPO);
                        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);

                    }
                }
            }
        }
        //刷新bill_detail统计数据
        getSIAccountService(user).refreshBillBatch(list.get(0).getPaymentOrganization(), list.get(0).getBillMonth());
        if (errorList.size() == 0) {
            result.put("data", "全部调差成功！");
        } else {
            result.put("data", "存在调差失败项！" + "失败数量为：" + errorList.size() + "。具体有以下：");
        }
        result.put("errorMessage", errorList);
        result.put("successIds", idList);
        return result;
    }

    @Override
    public String compensationConfigSave(List<InsuranceCompensationDTO> param) {
        long currentEmployeeId = user.getUID();

        SalaryAssert.notEmpty(param, SalaryI18nUtil.getI18nLabel(143746, "默认调差配置数据为空"));
        // 清除历史默认配置
        getInsuranceCompensationConfigMapper().deleteByPayOrg(param.get(0).getPaymentOrganization());
        // 保存历史默认配置
        List<InsuranceCompensationConfigPO> configList = param.stream().map(config -> {
            InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(config.getTarget());
            SalaryAssert.notNull(insuranceAccountDetailPO, SalaryI18nUtil.getI18nLabel(138849, "调差对象不存在"));
            return InsuranceCompensationConfigPO.builder()
                    .id(IdGenerator.generate())
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .employeeId(insuranceAccountDetailPO.getEmployeeId())
                    .adjustTo(config.getAdjustTo())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .categoryType(config.getCategoryType())
                    .paymentOrganization(config.getPaymentOrganization())
                    .welfareType(config.getWelfareType())
                    .deleteType(DeleteTypeEnum.NOT_DELETED.getValue())
                    .creator(currentEmployeeId).build();
        }).collect(Collectors.toList());
        configList.forEach(config -> getInsuranceCompensationConfigMapper().insert(config));
        //记录操作日志
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(param.get(0).getPaymentOrganization());
        LoggerContext<InsuranceCompensationConfigPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(param.get(0).getPaymentOrganization()));
        loggerContext.setTargetName(taxAgentInfo.getName());
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-保存社保调差默认配置"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-保存社保调差默认配置")
                + ":" + taxAgentInfo.getName());
        configList.forEach(loggerContext::setNewValues);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);

        return "配置成功";
    }

    /**
     * 社保调差撤回
     */
    @Override
    public String compensationRevert(InsuranceCompensationDTO param) {
        InsuranceCompensationPO insuranceCompensationPO = getInsuranceCompensationMapper().getById(param.getId());
        SalaryAssert.notNull(insuranceCompensationPO, SalaryI18nUtil.getI18nLabel(121112, "当前补差记录不存在"));
        InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getOneByBpep(InsuranceAccountDetailPO.builder()
                .billMonth(insuranceCompensationPO.getBillMonth())
                .paymentStatus(PaymentStatusEnum.COMMON.getValue())
                .employeeId(insuranceCompensationPO.getEmployeeId())
                .paymentOrganization(insuranceCompensationPO.getPaymentOrganization())
                .build());

        SalaryAssert.notNull(insuranceAccountDetailPO, SalaryI18nUtil.getI18nLabel(121108, "补差对象不存在"));
        encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
        if (StringUtils.isNotBlank(insuranceAccountDetailPO.getSocialComJson())) {
            Map<String, String> socialJson = JSON.parseObject(insuranceAccountDetailPO.getSocialComJson(), new HashMap<String, String>().getClass());
            for (Map.Entry<String, String> entry : socialJson.entrySet()) {
                String insuranceId = entry.getKey();
                String num = entry.getValue();
                if (Objects.equals(String.valueOf(insuranceCompensationPO.getAdjustTo()), insuranceId)) {
                    BigDecimal adjustmentTo = new BigDecimal(insuranceCompensationPO.getAdjustmentTotal());
                    //回退调差单位缴纳明细
                    BigDecimal insuranceNum = new BigDecimal(num);
                    insuranceNum = insuranceNum.subtract(adjustmentTo);
                    socialJson.replace(insuranceId, insuranceNum.toPlainString());
                    insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialJson));
                    //回退调差单位合计
                    BigDecimal comSum = new BigDecimal(insuranceAccountDetailPO.getComSum());
                    comSum = comSum.subtract(adjustmentTo);
                    insuranceAccountDetailPO.setComSum(comSum.toPlainString());
                    //回退调差社保单位合计
                    BigDecimal socialComSum = new BigDecimal(insuranceAccountDetailPO.getSocialComSum());
                    socialComSum = socialComSum.subtract(adjustmentTo);
                    insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
                    //回退调差社保合计
                    BigDecimal socialSum = new BigDecimal(insuranceAccountDetailPO.getSocialSum());
                    socialSum = socialSum.subtract(adjustmentTo);
                    insuranceAccountDetailPO.setSocialSum(socialSum.toPlainString());
                    //回退调差合计
                    BigDecimal totalSum = new BigDecimal(insuranceAccountDetailPO.getTotal());
                    totalSum = totalSum.subtract(adjustmentTo);
                    insuranceAccountDetailPO.setTotal(totalSum.toPlainString());
                    //更新社保调差后的明细
                    encryptUtil.encrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
                    getInsuranceAccountDetailMapper().updateById(insuranceAccountDetailPO);
                    //删除调差记录
                    getInsuranceCompensationMapper().deleteById(param.getId());

                }
            }
            //刷新bill_detail统计数据
            getSIAccountService(user).refreshBillBatch(param.getPaymentOrganization(), param.getBillMonth());

        }
        return "撤回成功";
    }

    @Override
    public Map<String, Object> compensationList(String billMonth, Long paymentOrganization) {

        Map<String, Object> datas = new HashMap<>();

        //入参判断
        if (paymentOrganization == null || StringUtils.isBlank(billMonth)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        //设置调差详情列表头
        List<WeaTableColumn> weaTableColumn = getColumnBuildService(user).buildCompensationColumns();
        WeaTable table = new WeaTable();
        table.setPageUID(UUID.randomUUID().toString());
        table.setColumns(weaTableColumn);
        List<Column> columns = weaTableColumn.stream().map(v -> new Column(v.getText(), v.getColumn(), v.getColumn())).collect(Collectors.toList());

        //处理调差数据
        List<InsuranceCompensationDTO> compensationDTOList = dealCompensationData(billMonth, paymentOrganization);

        datas.put("columns", columns);
        datas.put("data", compensationDTOList);

        return datas;
    }

    private List<InsuranceCompensationDTO> dealCompensationData(String billMonth, Long paymentOrganization) {

        //获取调差历史记录数据
        List<InsuranceCompensationPO> compensationPOList = getInsuranceCompensationMapper().queryByBillMonthAndPayOrg(billMonth, paymentOrganization);
        //获取调差配置数据
        List<InsuranceCompensationConfigPO> compensationConfigPOList = getInsuranceCompensationConfigMapper().queryByPayOrg(paymentOrganization);

        List<InsuranceCompensationDTO> compensationDTOList = new ArrayList<>();

        List<InsuranceAccountDetailPO> detailPOList = getInsuranceAccountDetailMapper().queryNormalListByBillMonth(billMonth, paymentOrganization);
        Map<Long, InsuranceAccountDetailPO> detailPOMap = detailPOList.stream().collect(Collectors.toMap(InsuranceAccountDetailPO::getEmployeeId, Function.identity()));

        List<DataCollectionEmployee> allEmployees = getEmployMapper().listAll();
        Map<Long, String> usernameMap = SalaryEntityUtil.convert2Map(allEmployees, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getUsername);

        List<ICategoryPO> allCategoryList = getICategoryMapper().listAll();
        Map<Long, String> categoryNameMap = SalaryEntityUtil.convert2Map(allCategoryList, ICategoryPO::getId, ICategoryPO::getInsuranceName);

        boolean haveCompensation = compensationPOList != null && compensationPOList.size() > 0;
        //存在调差历史记录时，输出记录数据
        if (haveCompensation) {
            for (InsuranceCompensationPO po : compensationPOList) {
                InsuranceCompensationDTO dto = new InsuranceCompensationDTO();
                BeanUtils.copyProperties(po, dto);
                dto.setStatus(true);
                //设置targetOptions
                Map<String,String> targetOptions = new HashMap<>();
                targetOptions.put("name", usernameMap.get(po.getEmployeeId()));
                targetOptions.put("id", detailPOMap.get(po.getEmployeeId()).getId().toString());

                dto.setTargetOptions(targetOptions);

                //设置categoryTypeOptions
                List<Map<String,String>> categoryTypeOptions = new ArrayList<>();
                List<String> categoryTypeList = Arrays.asList(po.getCategoryType().split(","));

                for (String categoryType : categoryTypeList) {
                    Map<String,String> categoryTypeMap = new HashMap<>();
                    categoryTypeMap.put("id", categoryType);
                    categoryTypeMap.put("content", categoryNameMap.get(Long.valueOf(categoryType)));
                    categoryTypeOptions.add(categoryTypeMap);
                }
                dto.setCategoryTypeOptions(categoryTypeOptions);

                compensationDTOList.add(dto);
            }
        }
        //不存在调差历史记录时，输出调差配置数据
        if (!haveCompensation && compensationConfigPOList.size() > 0) {
            for (InsuranceCompensationConfigPO configPO : compensationConfigPOList) {
                InsuranceCompensationDTO dto = new InsuranceCompensationDTO();
                BeanUtils.copyProperties(configPO, dto);
                dto.setStatus(false);
                //设置targetOptions
                Map<String,String> targetOptions = new HashMap<>();
                targetOptions.put("name", usernameMap.get(configPO.getEmployeeId()));
//                String target = detailPOMap.get(configPO.getEmployeeId()).getId().toString();
                String target = detailPOMap.get(configPO.getEmployeeId()) == null ? null : detailPOMap.get(configPO.getEmployeeId()).getId().toString();
                if (target == null) {
                    continue;
                } else {
                    targetOptions.put("id", detailPOMap.get(configPO.getEmployeeId()).getId().toString());
                }

                dto.setTargetOptions(targetOptions);

                //设置categoryTypeOptions
                List<Map<String,String>> categoryTypeOptions = new ArrayList<>();
                List<String> categoryTypeList = Arrays.asList(configPO.getCategoryType().split(","));

                for (String categoryType : categoryTypeList) {
                    Map<String,String> categoryTypeMap = new HashMap<>();
                    categoryTypeMap.put("id", categoryType);
                    categoryTypeMap.put("content", categoryNameMap.get(Long.valueOf(categoryType)));
                    categoryTypeOptions.add(categoryTypeMap);
                }
                dto.setCategoryTypeOptions(categoryTypeOptions);

                //设置公司核算金额（单位）
                CompensationParam compensationParam = CompensationParam.builder()
                        .categoryType(dto.getCategoryType())
                        .employeeId(dto.getEmployeeId().toString())
                        .paymentOrganization(dto.getPaymentOrganization())
                        .target(Long.valueOf(dto.getTargetOptions().get("id")))
                        .build();
                List<CompensationParam> paramList = new ArrayList<>();
                paramList.add(compensationParam);
                List<Map<String, String>> comTotalList = compensationComTotal(paramList);
                dto.setCompanyTotal(comTotalList.get(0).get("totalNum"));

                compensationDTOList.add(dto);
            }
        }

        return compensationDTOList;
    }

}
